<?php
/**
 * Created by PhpStorm.
 * Author: 芸签cms www.yunqiancms.com
 * User: sun
 * Date: 2022/8/10
 * Time: 9:49 AM
 */
namespace app\common\services;

use app\common\exceptions\BizException;
use app\common\facades\Setting;
use app\common\helpers\HttpHelper;
use Illuminate\Filesystem\Filesystem;
use app\common\helpers\Cache;

class AutoUpdate
{
    /**
     * Create new instance
     *
     * @param string $tempDir
     * @param string $installDir
     * @param int    $maxExecutionTime
     */
    public function __construct($tempDir = null, $installDir = null, $maxExecutionTime = 0)
    {
        $this->setTempDir(($tempDir !== null) ? $tempDir : storage_path('app/auto-update/temp'));
        $this->setInstallDir(($installDir !== null) ? $installDir : base_path());
        ini_set('max_execution_time', $maxExecutionTime);
    }
    /**
     * Set the temporary download directory.
     *
     * @param string $dir
     * @return $this|void
     */
    public function setTempDir($dir)
    {
        $dir = $this->addTrailingSlash($dir);
        if (!is_dir($dir)) {
            \Log::debug('Creating new temporary directory ', $dir);
            if (!mkdir($dir, 0755, true)) {
                \Log::debug('Could not create temporary directory ', $dir);
                return;
            }
        }
        return $this;
    }
    /**
     * Set the install directory.
     *
     * @param string $dir
     * @return $this|void
     */
    public function setInstallDir($dir)
    {
        $dir = $this->addTrailingSlash($dir);
        if (!is_dir($dir)) {
            \Log::debug('Creating new install directory ', $dir);
            if (!mkdir($dir, 0755, true)) {
                \Log::debug('Could not create install directory ', $dir);
                return;
            }
        }
        return $this;
    }
    public function getDirsByPath($path, Filesystem $filesystem = null)
    {
        $dirs = [];

        if (is_null($filesystem)) {
            $filesystem = app(Filesystem::class);
        }

        if ($all_dir = $filesystem->directories(base_path($path))) {
            if (!is_null($all_dir)) {
                foreach ($all_dir as $dir) {
                    $dirs[] = substr($dir, strrpos($dir, DIRECTORY_SEPARATOR)+1);
                }
            }
        }

        return $dirs;
    }
    /**
     * Add slash at the end of the path.
     *
     * @param string $dir
     * @return string
     */
    public function addTrailingSlash($dir)
    {
        if (substr($dir, -1) != DIRECTORY_SEPARATOR)
            $dir = $dir . DIRECTORY_SEPARATOR;
        return $dir;
    }
    public function checkDomain($params){
        $url = config('auto-update.domain') . '/register/check_domain';
        $content = HttpHelper::doPost($url,$params,$this->buildCurlHeader());
        return $this->buildCurlRes($content);
    }
    public function registerFree($params){
        $url = config('auto-update.domain') . '/register/free';
        $content = HttpHelper::doPost($url,$params,$this->buildCurlHeader());
        return $this->buildCurlRes($content);
    }
    public function sendSms($params){
        $url = config('auto-update.domain') . '/register/send_sms';
        $content = HttpHelper::doPost($url,$params,$this->buildCurlHeader());
        return $this->buildCurlRes($content);
    }
    public function appAccountCreate($params){
        $url = config('auto-update.domain') . '/update/app-account/create';
        $content = HttpHelper::doPost($url,$params,$this->buildCurlHeader());
        return $this->buildCurlRes($content);
    }
    public function appAccountCancel($params){
        $url = config('auto-update.domain') . '/update/app-account/cancel';
        $content = HttpHelper::doPost($url,$params,$this->buildCurlHeader());
        return $this->buildCurlRes($content);
    }
    /**
     * 获取token
     * @param $domain
     * @param $key
     * @param $secret
     * @return mixed
     */
    public function getToken(){
        $domain = request()->getHttpHost();
        $tokenCacheKey = 'app:common:services:AutoUpdate:getToken:'.$domain;
        $token = Cache::get($tokenCacheKey);
        if(!$token){
            $demand = ['domain' => $domain];
            $setting = Setting::get('cms.auth');
            if(!$setting['key']||!$setting['secret']){
                throw new BizException('系统未授权，请先授权注册');
            }
            $url = config('auto-update.domain') . '/public/get_token';
            $nonceStr = str_random();
            $header = [
                'Content-Type:application/json;charset=UTF-8',
                'Signature:'.$this->genSignature($setting['key'],$setting['secret'],$nonceStr),
                'nonceStr:'.$nonceStr,
            ];
            $content = HttpHelper::doPost($url,$demand,$header);
            $res = $this->buildCurlRes($content);
            $token = $res['data']['code'];
            Cache::put($tokenCacheKey,$token,30);
        }
        return $token;
    }
    /**
     * 检测指定的 key 和 密钥是否存在
     * @params string $fileName 检查路径
     * @params array $keyAndSecret ['key' => string, 'secret' => string]
     * @params array $postData post 传参
     * @return mixed
     */
    public function isKeySecretExists($postData, $message='') {
        $url = config('auto-update.domain') . '/update/check_key';
        $content = HttpHelper::doPost($url,$postData,$this->buildCurlTokenHeader());
        return $this->buildCurlRes($content);
    }

    /**
     * 获取已授权的插件列表
     * @param $domain
     * @return mixed
     */
    public function pluginInstallAuth($domain){
        $url = config('auto-update.domain') . '/plugin/plugin_install_auth';
        $content = HttpHelper::doPost($url,['domain' => $domain],$this->buildCurlTokenHeader());
        return $this->buildCurlRes($content);
    }

    /**
     * 检查组件是否授权
     * @param $name 组件名
     * @param $key
     * @param $secret
     * @return mixed
     */
    public function registerChkname($name){
        $url = config('auto-update.domain') . "/register/check_name";
        $content = HttpHelper::doPost($url,['name' => $name],$this->buildCurlTokenHeader());
        return $this->buildCurlRes($content);
    }

    /**
     * 根据domain获取应用市场所有插件列表
     * @param $domain
     * @return mixed
     */
    public function getAllPluginsByDomain($domain){
        $url = config('auto-update.domain') . '/plugin/domain';
        $content = HttpHelper::doPost($url,['domain' => $domain],$this->buildCurlHeader());
        return $this->buildCurlRes($content);
    }

    /**
     * @param $domain
     * @return mixed
     */
    public function pluginAuthorizeByDomain($domain){
        $url = config('auto-update.domain') . '/plugin/plugin_authorize';
        $content = HttpHelper::doPost($url,['domain' => $domain],$this->buildCurlHeader());
        return $this->buildCurlRes($content);
    }

    /**
     * 插件详情
     * @param $id
     * @param $domain
     * @return mixed
     */
    public function getPluginDetail($id, $domain){
        $demand = ['post_data' => ['id' => $id, 'domain' => $domain], 'work_order' => 1];
        $url = config('auto-update.domain') . '/plugin/get_detail';
        $content = HttpHelper::doPost($url,$demand,$this->buildCurlHeader());
        return $this->buildCurlRes($content);
    }

    /**
     * 检查插件是否存在
     * @param $domain
     * @param $pluginName
     * @return mixed
     */
    public function existsPlugin($domain,$pluginName){
        $url = config('auto-update.domain') . '/plugin/exists_plugin';
        $content = HttpHelper::doPost($url,['domain' => $domain,'name'=>$pluginName],$this->buildCurlTokenHeader());
        return $this->buildCurlRes($content);
    }
    /**
     * 获取插件下载地址及token
     * @param $domain
     * @param $pluginName
     * @return mixed
     */
    public function getPluginVersionByName($domain,$pluginName){
        $url = config('auto-update.domain') . '/plugin/version_info';
        $content = HttpHelper::doPost($url,['domain' => $domain,'name'=>$pluginName],$this->buildCurlTokenHeader());
        return $this->buildCurlRes($content);
    }
    /**
     * 根据domain获取应用市场所有插件列表
     * @param $domain
     * @return mixed
     */
    public function getAllThemes($domain){
        $url = config('auto-update.domain') . '/theme/all';
        $content = HttpHelper::doPost($url,['domain' => $domain],$this->buildCurlHeader());
        return $this->buildCurlRes($content);
    }
    /**
     * 插件详情
     * @param $id
     * @param $domain
     * @return mixed
     */
    public function getThemeDetail($id, $domain){
        $demand = ['post_data' => ['id' => $id, 'domain' => $domain], 'work_order' => 1];
        $url = config('auto-update.domain') . '/theme/get_detail';
        $content = HttpHelper::doPost($url,$demand,$this->buildCurlHeader());
        return $this->buildCurlRes($content);
    }

    /**
     * 安装模版
     * @param $id
     * @param $domain
     * @return mixed
     */
    public function themeInstall($id, $domain){
        $demand = ['post_data' => ['id' => $id, 'domain' => $domain]];
        $url = config('auto-update.domain') . '/theme/install';
        $content = HttpHelper::doPost($url,$demand,$this->buildCurlTokenHeader());
        return $this->buildCurlRes($content);
    }

    /**
     * @param $domain
     * @param $themeName
     * @return mixed
     * @throws BizException
     */
    public function getThemeVersionByName($domain,$themeName){
        $url = config('auto-update.domain') . '/theme/get_theme_version_by_name';
        $content = HttpHelper::doPost($url,['domain' => $domain,'name'=>$themeName],$this->buildCurlTokenHeader());
        return $this->buildCurlRes($content);
    }

    public function systemCheck(){
        $url = config('auto-update.domain') . "/update/system_check/";
        $content = HttpHelper::doPost($url,[],$this->buildCurlTokenHeader());
        return $this->buildCurlRes($content);
    }
    public function showLog($page){
        $url = config('auto-update.domain') . "/update/show_log/";
        $content = HttpHelper::doPost($url,[
            'page' => $page
        ],$this->buildCurlTokenHeader());
        return $this->buildCurlRes($content);
    }
    public function backendCheck($params){
        $url = config('auto-update.domain') . "/update/back_check_app";
        $content = HttpHelper::doPost($url,$params,$this->buildCurlTokenHeader());
        return $this->buildCurlRes($content);
    }
    public function appBackDownload($params,$key,$secret){
        $url = config('auto-update.domain') . "/update/back_download_app";
        $content = HttpHelper::doPost($url,$params,$this->buildCurlTokenHeader());
        return $this->buildCurlRes($content);
    }

    /**
     * 是否授权自动更新
     */
    public static function isAuto(){
        return config('auto-update.is_auto');
    }
    /**
     * curl请求头
     * @return array
     */
    private function buildCurlHeader(){
        return ["Content-Type:application/json;charset=UTF-8"];
    }
    /**
     * curl带鉴权请求头
     * @return array
     */
    private function buildCurlAuthHeader($key,$secret){
        $res = ["Content-Type:application/json;charset=UTF-8"];
        array_push($res,"Authorization: Basic " . base64_encode("{$key}:{$secret}"));
        return $res;
    }
    /**
     * curl带鉴权请求头
     * @return array
     */
    private function buildCurlTokenHeader(){
        $domain = request()->getHttpHost();
        $res = ["Content-Type:application/json;charset=UTF-8"];
        array_push($res,"Token:" . $this->getToken());
        array_push($res,"domain:" . $domain);
        return $res;
    }

    /**
     * 构造鉴权字符串
     * @param $key
     * @param $secret
     * @param $nonceStr
     * @return string
     */
    private function genSignature($key,$secret,$nonceStr){
        return md5($key.':'.$secret.':'.$nonceStr);
    }

    /**
     * curl返回接口
     * @param $res
     * @return mixed
     * @throws BizException
     */
    private function buildCurlRes($res){
        $res = json_decode($res,true);
        if($res['result']===0){
            //todo 统一格式
            throw new BizException($res['msg']);
        }
        return $res;
    }

}